/**
 *
 */
package de.cbf.cam.dsa.facet.garment.editor;

import java.beans.IndexedPropertyChangeEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;

import de.cbf.cam.dsa.facet.garment.FacetGarment;
import de.cbf.cam.dsa.facet.garment.act.ActivatorFacetGarment;
import de.cbf.cam.dsa.facet.garment.constants.WearPlaces;
import de.cbf.cam.dsa.facet.garment.editor.wear_places.CompositeWearPlaces;
import de.cbf.cam.dsa.facet.garment.editor.wear_places.ControllerWearPlaces;
import de.cbf.cam.dsa.facet.garment.interfaces.IGenderSpecific;
import de.cbf.util.entity.facet.edit.composites.factorys.AbstractFacetSectionFactory;
import de.cbf.util.entity.facet.edit.controller.AbstractControllerEditFacet;
import de.cbf.util.ui.listener.IUiChangeListener;
import de.cbf.util.ui.listener.UiChangeEvent;

/**
 * @author Nebelritter
 *
 */
public class ControllerEditorFacetGarment extends AbstractControllerEditFacet<FacetGarment> {
	private static final Log logger = LogFactory.getLog(ControllerEditorFacetGarment.class);
	
	public static final String TEXT_STATE_EVENT_Color_WARNING			= FacetGarment.TEXT_UNSET_COLOR;
	public static final String TEXT_STATE_EVENT_Material_WARNING		= FacetGarment.TEXT_UNSET_MATERIAL;
	public static final String TEXT_STATE_EVENT_Layer_ERROR				= "Layer setting not correct";
	public static final String TEXT_STATE_EVENT_Layer_WARNING			= FacetGarment.TEXT_UNSET_LAYER;
	public static final String TEXT_STATE_EVENT_LayerShiftIndex_ERROR	= "LayerShiftIndex setting not correct";
	public static final String TEXT_STATE_EVENT_LayerShiftIndex_WARNING	= FacetGarment.TEXT_UNSET_LAYER_SHIFT_INDEX;
	public static final String TEXT_STATE_EVENT_Gender_WARNING			= FacetGarment.TEXT_UNSET_SUITABLE_GENDER;
	public static final String TEXT_STATE_EVENT_WearPlaces_WARNING		= FacetGarment.TEXT_UNSET_COVERED_WEAR_PLACES;
	public static final String TEXT_STATE_EVENT_ColdResistance_ERROR	= "ColdResistance setting not correct";
	public static final String TEXT_STATE_EVENT_ColdResistance_WARNING	= FacetGarment.TEXT_UNSET_COLD_RESISTANCE;
	
	protected static StateEvent STATE_EVENT_Color_WARNING			= new StateEvent(TEXT_STATE_EVENT_Color_WARNING, StateEvent.STATE_WARNING);
	protected static StateEvent STATE_EVENT_Material_WARNING		= new StateEvent(TEXT_STATE_EVENT_Material_WARNING, StateEvent.STATE_WARNING);
	protected static StateEvent STATE_EVENT_Layer_ERROR 			= new StateEvent(TEXT_STATE_EVENT_Layer_ERROR, StateEvent.STATE_ERROR); 	
	protected static StateEvent STATE_EVENT_Layer_WARNING			= new StateEvent(TEXT_STATE_EVENT_Layer_WARNING, StateEvent.STATE_WARNING); 
	protected static StateEvent STATE_EVENT_LayerShiftIndex_ERROR 	= new StateEvent(TEXT_STATE_EVENT_LayerShiftIndex_ERROR, StateEvent.STATE_ERROR); 	
	protected static StateEvent STATE_EVENT_LayerShiftIndex_WARNING	= new StateEvent(TEXT_STATE_EVENT_LayerShiftIndex_WARNING, StateEvent.STATE_WARNING); 
	protected static StateEvent STATE_EVENT_Gender_WARNING			= new StateEvent(TEXT_STATE_EVENT_Gender_WARNING, StateEvent.STATE_WARNING);
	protected static StateEvent STATE_EVENT_WearPlaces_WARNING		= new StateEvent(TEXT_STATE_EVENT_WearPlaces_WARNING, StateEvent.STATE_WARNING);
	protected static StateEvent STATE_EVENT_ColdResistance_ERROR 	= new StateEvent(TEXT_STATE_EVENT_ColdResistance_ERROR, StateEvent.STATE_ERROR); 	
	protected static StateEvent STATE_EVENT_ColdResistance_WARNING	= new StateEvent(TEXT_STATE_EVENT_ColdResistance_WARNING, StateEvent.STATE_WARNING); 
	
	public static final String DIALOG_WEAR_PLACES_TEXT	= "WearPlaces";

	protected CompositeEditGarment 	compositeEditGarment;
	protected Map<Integer, String>	genderMap;

	protected NumberFormat format;
	
	/**
	 *
	 */
	public ControllerEditorFacetGarment() {
		super();
	}

	@Override
	protected void init() {
		super.init();
		format	= NumberFormat.getInstance();
		
		pclFacetGarment = new PCLFacetGarment();
		uilFacetGarment = new UILFacetGarment();
		initPossibleGenders();
	}

	protected void initPossibleGenders(){
		genderMap = new HashMap<Integer, String>();
		genderMap.put(IGenderSpecific.GENDER_UNKNOWN,IGenderSpecific.Util.getGenderText(IGenderSpecific.GENDER_UNKNOWN));
		genderMap.put(IGenderSpecific.GENDER_FEMALE	,IGenderSpecific.Util.getGenderText(IGenderSpecific.GENDER_FEMALE));
		genderMap.put(IGenderSpecific.GENDER_MALE	,IGenderSpecific.Util.getGenderText(IGenderSpecific.GENDER_MALE));
	}


	@Override
	protected AbstractFacetSectionFactory createSectionFactory() {
		return new SectionFactoryGarment();
	}

	@Override
	protected FacetGarment createNewFacet() {
		FacetGarment facet = new FacetGarment();
		return facet;
	}

	@Override
	public Class<FacetGarment> getFacetClass() {
		return FacetGarment.class;
	}
	
	public void handleEditWearPlaces() {
		//open window for edit of wear places

		//create dialog
		Shell parentShell = ActivatorFacetGarment.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell();

		DialogWearPlaces dialog_WearPlaces = new DialogWearPlaces(parentShell,DIALOG_WEAR_PLACES_TEXT);
		dialog_WearPlaces.setBlockOnOpen(true);
		int result = dialog_WearPlaces.open();
		if(result == DialogWearPlaces.OK){
			facet.setCoveredWearPlaces(dialog_WearPlaces.getChosen());
		}
	}

	public void handleSelectedGender() {
		String genderString = compositeEditGarment.getSelectedGender();//LATER see if double hashmap would be better		
		for (Integer genderIndex : genderMap.keySet()) {
			String gender = genderMap.get(genderIndex);
			if(gender.equals(genderString)){
				facet.setGender(genderIndex);
			}
		}
	}

	public void modifyColor(String color) {
		if(facet == null) return;
		facet.setColor(color);
	}

	public void modifyMaterial(String material) {
		if(facet == null) return;
		facet.setMaterial(material);
	}
	
	public void modifyLayer(String newLayer) {	
		if(facet == null) return;	
		Number valueNumber;
		try {
			if(compositeEditGarment != null){
				compositeEditGarment.setDecorationLayerStatus(false);
			}
			removeStateEvent(STATE_EVENT_Layer_ERROR);
			valueNumber =  format.parse(newLayer);		
			if (valueNumber instanceof Integer) {
				Integer valueInteger = (Integer) valueNumber;
				facet.setLayer(valueInteger.doubleValue());
			}
			if (valueNumber instanceof Double) {
				Double valueDouble = (Double) valueNumber;
				facet.setLayer(valueDouble);
			}
		} catch (ParseException e) {
			if(compositeEditGarment != null){
				compositeEditGarment.setDecorationLayerStatus(true);	
			}
			addStateEvent(STATE_EVENT_Layer_ERROR);			
		}	
	}
	
	public void modifyLayerShiftIndex(String newLayerShiftIndex) {	
		if(facet == null) return;	
		Number valueNumber;
		try {
			if(compositeEditGarment != null){
				compositeEditGarment.setDecorationLayerShiftIndexStatus(false);
			}
			removeStateEvent(STATE_EVENT_LayerShiftIndex_ERROR);
			valueNumber =  format.parse(newLayerShiftIndex);		
			if (valueNumber instanceof Integer) {
				Integer valueInteger = (Integer) valueNumber;
				facet.setLayerShiftIndex(valueInteger.doubleValue());
			}
			if (valueNumber instanceof Double) {
				Double valueDouble = (Double) valueNumber;
				facet.setLayerShiftIndex(valueDouble);
			}
		} catch (ParseException e) {
			if(compositeEditGarment != null){
				compositeEditGarment.setDecorationLayerShiftIndexStatus(true);	
			}
			addStateEvent(STATE_EVENT_LayerShiftIndex_ERROR);			
		}	
	}

	public void modifyColdResistance(String newColdResistance) {	
		if(facet == null) return;	
		Number valueNumber;
		try {
			if(compositeEditGarment != null){
				compositeEditGarment.setDecorationColdResistanceStatus(false);
			}
			removeStateEvent(STATE_EVENT_ColdResistance_ERROR);
			valueNumber =  format.parse(newColdResistance);		
			if (valueNumber instanceof Integer) {
				Integer valueInteger = (Integer) valueNumber;
				facet.setColdResistance(valueInteger.doubleValue());
			}
			if (valueNumber instanceof Double) {
				Double valueDouble = (Double) valueNumber;
				facet.setColdResistance(valueDouble);
			}
		} catch (ParseException e) {
			if(compositeEditGarment != null){
				compositeEditGarment.setDecorationColdResistanceStatus(true);	
			}
			addStateEvent(STATE_EVENT_ColdResistance_ERROR);			
		}	
	}
	
	public void updateColor(String newColor) {
		if(newColor != null && compositeEditGarment != null){
			if( ! newColor.equals(FacetGarment.UNSET_COLOR)){
				compositeEditGarment.setColor(newColor);
				removeStateEvent(STATE_EVENT_Color_WARNING);
			}else{
				compositeEditGarment.setMaterial("");
				addStateEvent(STATE_EVENT_Color_WARNING);
			}			
		}		
	}

	public void updateMaterial(String newMaterial) {
		if(newMaterial != null && compositeEditGarment != null){
			if( ! newMaterial.equals(FacetGarment.UNSET_MATERIAL)){
				compositeEditGarment.setMaterial(newMaterial);
				removeStateEvent(STATE_EVENT_Material_WARNING);
			}else{
				compositeEditGarment.setMaterial("");
				addStateEvent(STATE_EVENT_Material_WARNING);
			}			
		}		
	}
	
	public void updateLayer(Double newLayer) {
		if(newLayer != null && compositeEditGarment != null){
			if( ! newLayer.equals(FacetGarment.UNSET_LAYER)){				
				compositeEditGarment.setLayer(format.format(newLayer));
				removeStateEvent(STATE_EVENT_Layer_WARNING);
			}else{
				compositeEditGarment.setLayer("");
				addStateEvent(STATE_EVENT_Layer_WARNING);
			}				
		}			
	}
	
	public void updateLayerShiftIndex(Double newLayerShiftIndex) {
		if(newLayerShiftIndex != null && compositeEditGarment != null){
			if( ! newLayerShiftIndex.equals(FacetGarment.UNSET_LAYER_SHIFT_INDEX)){				
				compositeEditGarment.setLayerShiftIndex(format.format(newLayerShiftIndex));
				removeStateEvent(STATE_EVENT_LayerShiftIndex_WARNING);
			}else{
				compositeEditGarment.setLayerShiftIndex("");
				addStateEvent(STATE_EVENT_LayerShiftIndex_WARNING);
			}				
		}			
	}
	
	
	public void updateGender(Integer newGender) {
		if(newGender != null && compositeEditGarment != null){
			String selectedGender = genderMap.get(newGender);
			compositeEditGarment.setSelectedGender(selectedGender);
			if( ! newGender.equals(FacetGarment.UNSET_SUITABLE_GENDER)){
				removeStateEvent(STATE_EVENT_Gender_WARNING);
			}else{				
				addStateEvent(STATE_EVENT_Gender_WARNING);
			}
		}		
	}

	public void updateWearPlaces(List<?> wearPlaces) {
		List<String> wearPlaceList = new ArrayList<String>();
		for (Object object : wearPlaces) {
			if (object instanceof String) {
				String place = (String) object;
				wearPlaceList.add(place);
			}
		}
		if(compositeEditGarment != null){
			compositeEditGarment.setWearPlaces(wearPlaceList);
		}	
		if ( ! wearPlaces.equals(FacetGarment.UNSET_COVERED_WEAR_PLACES)) {
			removeStateEvent(STATE_EVENT_WearPlaces_WARNING);
		}else{
			addStateEvent(STATE_EVENT_WearPlaces_WARNING);
		}
	}
	
	public void updateColdResistance(Double newColdResistance) {
		if(newColdResistance != null && compositeEditGarment != null){
			if( ! newColdResistance.equals(FacetGarment.UNSET_COLD_RESISTANCE)){				
				compositeEditGarment.setColdResistance(format.format(newColdResistance));
				removeStateEvent(STATE_EVENT_ColdResistance_WARNING);
			}else{
				compositeEditGarment.setColdResistance("");
				addStateEvent(STATE_EVENT_ColdResistance_WARNING);
			}				
		}			
	}
	
	@Override
	protected void updateAll(FacetGarment facet) {	
		updateColor(facet.getColor());
		updateMaterial(facet.getMaterial());
		updateLayer(facet.getLayer());
		updateLayerShiftIndex(facet.getLayerShiftIndex());
		updateGender(facet.getGender());
		updateWearPlaces(facet.getCoveredWearPlaces());
		updateColdResistance(facet.getColdResistance());			
	}
	
	@Override
	protected void updateClearUI() {
		updateColor(FacetGarment.UNSET_COLOR);
		updateMaterial(FacetGarment.UNSET_MATERIAL);
		updateLayer(FacetGarment.UNSET_LAYER);
		updateLayerShiftIndex(FacetGarment.UNSET_LAYER_SHIFT_INDEX);
		updateGender(FacetGarment.UNSET_SUITABLE_GENDER);
		updateWearPlaces(FacetGarment.UNSET_COVERED_WEAR_PLACES);
		updateColdResistance(FacetGarment.UNSET_COLD_RESISTANCE);
	}


	@Override
	protected void preSetSection() {
		super.preSetSection();
		if(section != null){
			Control client = section.getClient();
			if (client instanceof CompositeEditGarment) {
				compositeEditGarment = (CompositeEditGarment) client;
				deRegisterUIListeners(compositeEditGarment);
			}else{
				logger.error("wrong client in section: expected "+CompositeEditGarment.class.getSimpleName()+
						" got: "+client.getClass().getSimpleName());
			}
		}
	}

	@Override
	protected void postSetSection() {
		super.postSetSection();
		Control client = section.getClient();
		if (client instanceof CompositeEditGarment) {
			compositeEditGarment = (CompositeEditGarment) client;
			registerUIListeners(compositeEditGarment);
			updatePossibleGenders();
		}else{
			logger.error("wrong client in section: expected "+CompositeEditGarment.class.getSimpleName()+
					" got: "+client.getClass().getSimpleName());
		}
	}

	protected void updatePossibleGenders() {
		compositeEditGarment.setPossibleGenders(new ArrayList<String>(genderMap.values()));
	}

	protected void registerUIListeners(CompositeEditGarment compositeCategory) {
		compositeCategory.registerUIListener(uilFacetGarment);
	}

	protected void deRegisterUIListeners(CompositeEditGarment compositeCategory) {
		compositeCategory.deRegisterUIListener(uilFacetGarment);
	}

	@Override
	protected void preSetNewFacet() {
		super.preSetNewFacet();
		if(facet != null){
			deRegisterModelListeners(facet);
		}
	}

	@Override
	protected void postSetNewFacet() {
		super.postSetNewFacet();
		if(facet != null){
			registerModelListeners(facet);
		}
	}

	protected void registerModelListeners(FacetGarment facet) {
		facet.getPropertyChangeSupport().addPropertyChangeListener(pclFacetGarment);
	}

	protected void deRegisterModelListeners(FacetGarment facet) {
		facet.getPropertyChangeSupport().removePropertyChangeListener(pclFacetGarment);
	}

	protected UILFacetGarment uilFacetGarment;
	protected class UILFacetGarment implements IUiChangeListener{
		@Override
		public void uiChanged(UiChangeEvent event) {
			int index = event.getIndex();
			switch (index) {
				case CompositeEditGarment.IDX_COLOR:{
					Object obj = event.getNewValue();
					if (obj instanceof String) {
						String color = (String) obj;
						modifyColor(color);
					}
					break;
				}
				case CompositeEditGarment.IDX_MATERIAL:{
					Object obj = event.getNewValue();
					if (obj instanceof String) {
						String material = (String) obj;
						modifyMaterial(material);
					}
					break;
				}
				case CompositeEditGarment.IDX_LAYER:{
					Object obj = event.getNewValue();
					if (obj instanceof String) {
						String layer = (String) obj;
						modifyLayer(layer);
					}
					break;
				}
				case CompositeEditGarment.IDX_LAYER_SHIFT_INDEX:{
					Object obj = event.getNewValue();
					if (obj instanceof String) {
						String layerShiftIndex = (String) obj;
						modifyLayerShiftIndex(layerShiftIndex);
					}
					break;
				}
				case CompositeEditGarment.IDX_COLD_RESISTANCE:{
					Object obj = event.getNewValue();
					if (obj instanceof String) {
						String coldResistance = (String) obj;
						modifyColdResistance(coldResistance);
					}
					break;
				}
				default:
					break;
			}
		}

		@Override
		public void commandIssued(int index, Object... parameters) {
			switch (index) {
				case CompositeEditGarment.CMD_SELECTED_GENDER:
					handleSelectedGender();
					break;
				case CompositeEditGarment.CMD_EDIT_WEAR_PLACES:
					handleEditWearPlaces();
					break;
				default:
					logger.error("unknown commandIndex: "+index);
					break;
			}
		}
	}

	protected PCLFacetGarment pclFacetGarment;
	protected class PCLFacetGarment implements PropertyChangeListener{

		@Override
		public void propertyChange(PropertyChangeEvent evt) {
			if (evt instanceof IndexedPropertyChangeEvent) {
				IndexedPropertyChangeEvent idxEvt = (IndexedPropertyChangeEvent) evt;
				switch (idxEvt.getIndex()) {
					case FacetGarment.PI_SUITABLE_GENDER:{
						if (idxEvt.getNewValue() instanceof Integer) {
							Integer gender = (Integer) idxEvt.getNewValue();
							updateGender(gender );
						}
						break;
					}
					case FacetGarment.PI_COLOR:{
						if (idxEvt.getNewValue() instanceof String) {
							String color = (String) idxEvt.getNewValue();
							updateColor(color);
						}
						break;
					}
					case FacetGarment.PI_MATERIAL:{
						if (idxEvt.getNewValue() instanceof String) {
							String material = (String) idxEvt.getNewValue();
							updateMaterial(material);
						}
						break;
					}
					case FacetGarment.PI_LAYER:{
						if (idxEvt.getNewValue() instanceof Double) {
							Double layer = (Double) idxEvt.getNewValue();
							updateLayer(layer);
						}
						break;
					}
					case FacetGarment.PI_LAYER_SHIFT_INDEX:{
						if (idxEvt.getNewValue() instanceof Double) {
							Double layerShiftIndex = (Double) idxEvt.getNewValue();
							updateLayerShiftIndex(layerShiftIndex);
						}
						break;
					}
					case FacetGarment.PI_COLD_RESISTANCE:{
						if (idxEvt.getNewValue() instanceof Double) {
							Double coldResistance = (Double) idxEvt.getNewValue();
							updateColdResistance(coldResistance);
						}
						break;
					}
					case FacetGarment.PI_COVERED_WEAR_PLACES:{
						if (idxEvt.getNewValue() instanceof List<?>) {
							List<?> wearPlaces = (List<?>) idxEvt.getNewValue();
							updateWearPlaces(wearPlaces);
						}
						break;
					}

					default:
						break;
				}
			}
		}
	}

	protected class DialogWearPlaces extends Dialog{
		//LATER make dialog more beautiful, like form dialog
		protected ControllerWearPlaces controllerWearPlaces;

		protected String shellTitle = null;

		protected Button bt_Ok;
		protected Button bt_Cancel;

		protected DialogWearPlaces(Shell parentShell, String shellTitle) {
			super(parentShell);
			this.shellTitle = shellTitle;
			init();
		}

		protected void init(){
			controllerWearPlaces = new ControllerWearPlaces();
		}

		/*
	     * (non-Javadoc)
	     *
	     * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
	     */
	    protected void configureShell(Shell shell) {
	        super.configureShell(shell);
	        if (shellTitle != null) {
				shell.setText(shellTitle);
			}
	    }

		@Override
		protected Control createDialogArea(Composite parent) {
			// create compositeEditGarment
	        Composite compositeArea = (Composite) super.createDialogArea(parent);

			CompositeWearPlaces compositeWearPlaces = new CompositeWearPlaces(compositeArea, SWT.DOUBLE_BUFFERED, compositeEditGarment.getToolkit());
			compositeWearPlaces.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

			controllerWearPlaces.setComposite(compositeWearPlaces);
			controllerWearPlaces.setPossible(WearPlaces.getAllWearPlaces());
			controllerWearPlaces.setChosen(facet.getCoveredWearPlaces());
			return compositeWearPlaces;
		}
		/*
	     * (non-Javadoc)
	     *
	     * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
	     */
	    protected void createButtonsForButtonBar(Composite parent) {
	        // create OK and Cancel buttons by default
	        bt_Ok = createButton(parent, IDialogConstants.OK_ID,
	                IDialogConstants.OK_LABEL, true);
	        bt_Cancel = createButton(parent, IDialogConstants.CANCEL_ID,
	                IDialogConstants.CANCEL_LABEL, false);
	    }

		public List<String> getChosen() {
			return controllerWearPlaces.getChosen();
		}
	}
}
